Description:
Express Setup
首先,安裝 express globallynpm install -g express
修改package.json,加入dependencies,一一列出要install的package,改完存檔
"*": 代表要最新版本
{
"name": "2_express_website",
"version": "1.0.0",
"description": "Simple website",
"main": "app.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "gogocatmario",
"license": "ISC",
"dependencies": {
"body-parser": "*",
"express": "*",
"jade": "*",
"nodemailer": "*"
}
}
執行batch install
npm會把dependencies列出的所有module都install到project目錄npm install
Express Example
撰寫app.js,並執行server,打開網頁確認是否有畫面,且console有show log
var express = require('express');
var path = require('path');
var bodyParser = require('body-parser');
var nodemailer = require('nodemailer');
var app = express();
//set up middleware
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: false}));
app.listen(3000);
console.log('Server is running on port 3000...')
因為此時尚未有routing,所以網頁打開會show Cannot GET/
不過先驗證網頁開得起來就行了。
接下來,加入routing
var express = require('express');
var path = require('path');
var bodyParser = require('body-parser');
var nodemailer = require('nodemailer');
var app = express();
//set up middleware
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: false}));
//routing
app.get('/', function(req, res){
res.send("<h1>Hello world from res</h1>");
console.log("Hello world from console");
});
app.listen(3000);
console.log('Server is running on port 3000....');
確認網頁有出現 Hello World,就可以往下一步了。
Page Routes & Views (using Jade)
Jade Setup (加到app.js)
//views
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
修改 routing (res.send 改成 res.render)
//routing
app.get('/', function(req, res){
res.render('index');
});
create views 資料夾,用來放jade views
建立index.jadeh3 Hello World
相關連結:
Jade example:
https://naltatis.github.io/jade-syntax-docs/
Jade Convertor:
http://html2jade.org/
上面是簡單的jade使用範例
可以建立一個範本,讓每個jade文件reuse,不需要所有jade都包含完整的code
建立layout.jade,用來當作所有views的範本
doctype html
html
head
title my jade template
body
h1 Hello World
修改index.jade,開始參考layout.jade,只有block content的位置內容不同
extends layout
block content
h3 Hello World
為layout.jade加入bootstrap css
create public 資料夾,在public中建立stylesheet資料夾用來放css
將download下來的bootstrap.css copy到stylesheet中
目錄會長得像這樣:
express_website
-node_modules
-public
-stylesheet
bootstrap.css
-views
index.jade
layout.jade
app.js
package.json
修改app.js
//stylesheet
app.use(express.static(path.join(__dirname, 'public')));
使用jumbotron example建立website
http://getbootstrap.com/getting-started/#examples
from: jumbotron + Starter template
開新文件,copy jumbotron html過來,並修改以下幾個地方:<a class="navbar-brand" href="#">PC Repairs</a>
從Starter template複製ul,並修改:
<ul class="nav navbar-nav">
<li><a href="/">Home</a></li>
<li><a href="/about">About</a></li>
<li><a href="/contact">Contact</a></li>
</ul>
head 中加入bootstrap<link href="stylesheet/bootstrap.css" rel="stylesheet">
移除不需要的內容後,結果如下
<!DOCTYPE html>
<html>
<head>
<title>Jumbotron Template for Bootstrap</title>
<!-- Bootstrap core CSS -->
<link href="/stylesheet/bootstrap.css" rel="stylesheet">
</head>
<body>
<nav class="navbar navbar-inverse navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">PC Repairs</a>
</div>
<div id="navbar" class="collapse navbar-collapse">
<ul class="nav navbar-nav">
<li><a href="/">Home</a></li>
<li><a href="/about">About</a></li>
<li><a href="/contact">Contact</a></li>
</ul>
</div><!--/.navbar-collapse -->
</div>
</nav>
<!-- Main jumbotron for a primary marketing message or call to action -->
<div class="jumbotron">
<div class="container">
<h1>Hello, world!</h1>
<p>This is a template for a simple marketing or informational website. It includes a large callout called a jumbotron and three supporting pieces of content. Use it as a starting point to create something more unique.</p>
<p><a class="btn btn-primary btn-lg" href="#" role="button">Learn more »</a></p>
</div>
</div>
<div class="container">
<!-- Example row of columns -->
<div class="row">
<div class="col-md-4">
<h2>Heading</h2>
<p>Donec id elit non mi porta gravida at eget metus. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Etiam porta sem malesuada magna mollis euismod. Donec sed odio dui. </p>
<p><a class="btn btn-default" href="#" role="button">View details »</a></p>
</div>
<div class="col-md-4">
<h2>Heading</h2>
<p>Donec id elit non mi porta gravida at eget metus. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Etiam porta sem malesuada magna mollis euismod. Donec sed odio dui. </p>
<p><a class="btn btn-default" href="#" role="button">View details »</a></p>
</div>
<div class="col-md-4">
<h2>Heading</h2>
<p>Donec sed odio dui. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Vestibulum id ligula porta felis euismod semper. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus.</p>
<p><a class="btn btn-default" href="#" role="button">View details »</a></p>
</div>
</div>
<hr>
<footer>
<p>© 2016 Company, Inc.</p>
</footer>
</div> <!-- /container -->
</body>
</html>
copy 改好的 html 到 Jade Convertor,copy output jade to layout.jade
doctype html
html
head
title Jumbotron Template for Bootstrap
// Bootstrap core CSS
link(href='/stylesheet/bootstrap.css', rel='stylesheet')
body
nav.navbar.navbar-inverse.navbar-fixed-top
.container
.navbar-header
button.navbar-toggle.collapsed(type='button', data-toggle='collapse', data-target='#navbar', aria-expanded='false', aria-controls='navbar')
span.sr-only Toggle navigation
span.icon-bar
span.icon-bar
span.icon-bar
a.navbar-brand(href='#') PC Repairs
#navbar.collapse.navbar-collapse
ul.nav.navbar-nav
li
a(href='/') Home
li
a(href='/about') About
li
a(href='/contact') Contact
// /.navbar-collapse
// Main jumbotron for a primary marketing message or call to action
.jumbotron
.container
h1 Hello, world!
p
| This is a template for a simple marketing or informational website. It includes a large callout called a jumbotron and three supporting pieces of content. Use it as a starting point to create something more unique.
p
a.btn.btn-primary.btn-lg(href='#', role='button') Learn more »
.container
// Example row of columns
.row
.col-md-4
h2 Heading
p
| Donec id elit non mi porta gravida at eget metus. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Etiam porta sem malesuada magna mollis euismod. Donec sed odio dui.
p
a.btn.btn-default(href='#', role='button') View details »
.col-md-4
h2 Heading
p
| Donec id elit non mi porta gravida at eget metus. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Etiam porta sem malesuada magna mollis euismod. Donec sed odio dui.
p
a.btn.btn-default(href='#', role='button') View details »
.col-md-4
h2 Heading
p
| Donec sed odio dui. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Vestibulum id ligula porta felis euismod semper. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus.
p
a.btn.btn-default(href='#', role='button') View details »
hr
footer
p © 2016 Company, Inc.
// /container
layout.jade中的main jumbotron段落應該只在index頁面出現
因此將 main jumbotron內容copy到 index.jade
要剪下的部份
// Main jumbotron for a primary marketing message or call to action
.jumbotron
.container
h1 Hello World
p
| This is a template for a simple marketing or informational website. It includes a large callout called a jumbotron and three supporting pieces of content. Use it as a starting point to create something more unique.
p
a.btn.btn-primary.btn-lg(href='#', role='button') Learn more »
.container
// Example row of columns
.row
.col-md-4
h2 Heading
p
| Donec id elit non mi porta gravida at eget metus. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Etiam porta sem malesuada magna mollis euismod. Donec sed odio dui.
p
a.btn.btn-default(href='#', role='button') View details »
.col-md-4
h2 Heading
p
| Donec id elit non mi porta gravida at eget metus. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Etiam porta sem malesuada magna mollis euismod. Donec sed odio dui.
p
a.btn.btn-default(href='#', role='button') View details »
.col-md-4
h2 Heading
p
| Donec sed odio dui. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Vestibulum id ligula porta felis euismod semper. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus.
p
a.btn.btn-default(href='#', role='button') View details »
在layout.jade剪下的位置加入 block content
(記得空格位置要對齊,不然jade轉html時會搞錯)
...
// /.nav-collapse
block content
hr
footer
...
置中footer,加入class="text-center"
...
footer
p(class="text-center") © 2016 Company, Inc.
// /container
在 index.jade 使用參數代入值
修改routing,加入title參數
//routing
app.get('/', function(req, res){
res.render('index', {title: 'Welcome'});
});
修改index.jade,把 Hello World 改成代入參數的格式
...
.jumbotron
.container
h1 #{title}
p
...
如此一來,index page 就設定好了,接下來加入 about page
修改app.js,加入about routing
app.get('/about', function(req, res){
res.render('about');
});
create about.jade
p 裡面需要在T前面加上pipeline,不然jade convert時會以為是Tab,就只會show "is the ..."
extends layout
block content
h1 About Us
p
|This is the about page
到這裡,index page 和 about page 都設定完成。
Nodemailer Module
接下來要create contact page
修改app.js,加入contact的routing
app.get('/contact', function(req, res){
res.render('contact');
});
create contact.jade,建立表單
extends layout
block content
.container
form(method='post', action='contact/send')
h1 Contact
.form-group
label Name
input.form-control(type='text',
name='name', placeholder='Enter Name')
.form-group
label Email
input.form-control(type='email',
name='email', placeholder='Enter Email')
.form-group
label Message
textarea.form-control(name='message', placeholder='Enter Message')
button.btn.btn-default(type='Submit') Submit
Contact 畫面長得像這樣
當點選Submit button時,會透過POST送出request
針對POST request,需要撰寫對應的server動作
修改app.js,加入POST request routing
其中的 user / pass / from 需填寫寄件者的gmail 帳戶和密碼
to 的內容則填寫收件者的 gmail 帳戶
app.post('/contact/send', function(req, res){
//console.log('Test');
//specify server options
var transporter = nodemailer.createTransport({
service: 'Gmail',
auth: {
user: 'your gmail',
pass: 'your gmail password'
}
});
//setup mail options
var mailOptions = {
from: 'Your Name <your gmail>',
to: 'your gmail',
subject: 'Website Submission',
text: 'You have a submission with the following details... Name: ' + req.body.name + 'Email: ' + req.body.email + 'Message: ' + req.body.message,
html: '<p>You have a submission with the following details...</p><ul><li>Name: '+req.body.name+'</li><li>Email: '+req.body.email+'</li><li>Message: '+req.body.message+'</li></ul>'
};
transporter.sendMail(mailOptions, function(error, info){
if(error){
console.log(error);
res.redirect('/');
} else {
console.log('Message Sent: ' + info.response);
res.redirect('/');
}
});
});
註:
講者有提示,目前nodemailer應該只support gmail engine
其他家的email或是自己的SMTP,還沒辦法用nodemailer
到gmail暫時開啟低安全程式存取權限(不然gmail不給寄信),測試完之後記得改回來
(google 關鍵字: gmail access for less secure apps)
接著啟動server,填寫contact form按submit,就可以到 gmail 去收信了
最後修改幾個地方練習一下改jade,結束這回合。
app.js
app.get('/', function(req, res){
res.render('index', {title: 'Computer Not Working?'});
});
index.jade
...
.container
// Example row of columns
.row
.col-md-4
h2 Virus Removal
....
h2 Hardware Issues
....
h2 Software Issues
....